package com.runlooker.runer.views;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;

public class ZoomImageView extends ImageView implements OnGlobalLayoutListener,
		OnScaleGestureListener, OnTouchListener {
	private static final String tag = ZoomImageView.class.getSimpleName();

	/**
	 * 初始化操作
	 */
	private boolean mOnce;

	/**
	 * 初始化时的缩放值
	 */
	private float mInitScale;

	/**
	 * 双击放大值到到达的值
	 */
	private float mMidScale;

	/**
	 * 放大的最大值
	 */
	private float mMaxScale;

	private Matrix mScaleMatix;

	private ScaleGestureDetector mScaleGestureDetector;

	// -------------自由移动
	/**
	 * 记录上一次多点触控的数量
	 */
	private int mLastPointerCount;

	private float mLastX;
	private float mLastY;

	private int mTouchSlop;
	private boolean isCanDrag;

	private boolean isCheckLeftAndRight;
	private boolean isCheckTopAndBottom;

	public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO Auto-generated constructor stub
		mScaleMatix = new Matrix();

		mScaleGestureDetector = new ScaleGestureDetector(context, this);
		setOnTouchListener(this);

		// 偏移量超过mTouchSlop，则认为用户移动
		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
	}

	public ZoomImageView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public ZoomImageView(Context context) {
		this(context, null);
	}

	@Override
	protected void onAttachedToWindow() {
		// TODO Auto-generated method stub
		super.onAttachedToWindow();
		getViewTreeObserver().addOnGlobalLayoutListener(this);
	}

	@SuppressLint("NewApi")
	@Override
	protected void onDetachedFromWindow() {
		// TODO Auto-generated method stub
		super.onDetachedFromWindow();
		getViewTreeObserver().removeGlobalOnLayoutListener(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.view.ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout()
	 */
	@Override
	public void onGlobalLayout() {
		if (!mOnce) {
			// 得到空间的宽和高
			int width = getWidth();
			int height = getHeight();

			// 得到图片，以及图片的宽和高
			Drawable d = getDrawable();
			if (d == null) {
				return;
			}

			int dw = d.getIntrinsicWidth();
			int dh = d.getIntrinsicHeight();

			float scale = 1.0f;

			// 图片宽度大于控件宽度，但是高度小于控件高度，将其缩小
			if (dw > width && dh < height) {
				scale = width * 1.0f / dw;
			}

			// 图片高度大于控件高度，但是宽度小于控件宽度，将其缩小
			if (dh > height && dw < width) {
				scale = height * 1.0f / dh;
			}

			// 图片宽和高都大于控件或都小于空间，则取比例的最小值
			if ((dw > width && dh > height) || (dw < width && dh < height)) {
				scale = Math.min(width * 1.0f / dw, height * 1.0f / dw);
			}
			/**
			 * 得到了初始化时的缩放值比例
			 */
			mInitScale = scale;
			mMaxScale = mInitScale * 4;
			mMidScale = mInitScale * 2;

			/**
			 * 将图片移动到当前控件的中心
			 */

			int dx = getWidth() / 2 - dw / 2;
			int dy = getHeight() / 2 - dh / 2;
			mScaleMatix.postTranslate(dx, dy);
			mScaleMatix
					.postScale(mInitScale, mInitScale, width / 2, height / 2);
			setImageMatrix(mScaleMatix);
			mOnce = true;
		}
	}

	/**
	 * 
	 * 获得当前图片缩放值
	 * 
	 * @return
	 */
	public float getScale() {
		float[] values = new float[9];
		mScaleMatix.getValues(values);
		return values[Matrix.MSCALE_X];
	}

	// 缩放区间：initScale maxScale
	@Override
	public boolean onScale(ScaleGestureDetector detector) {
		float scale = getScale();
		float scaleFactor = detector.getScaleFactor();
		if (getDrawable() == null) {
			return true;
		}

		if ((scale < mMaxScale && scaleFactor > 1.0f)
				|| (scale > mInitScale && scaleFactor < 1.0f)) {
			if (scale * scaleFactor < mInitScale) {
				scaleFactor = mInitScale / scale;
			}

			if (scale * scaleFactor > mMaxScale) {
				scaleFactor = mMaxScale / scale;
			}
			Log.i(tag, "scaleFactor:    " + scaleFactor);
			Log.i(tag, "scale:    " + scale);
			mScaleMatix.postScale(scaleFactor, scaleFactor,
					detector.getFocusX(), detector.getFocusY());
			checkBorderAndCenterWhenScale();
			setImageMatrix(mScaleMatix);
		}

		return true;
	}

	public void checkBorderAndCenterWhenScale() {
		RectF rect = getMatrixRectF();
		float deltaX = 0;
		float deltaY = 0;
		float width = getWidth();
		float height = getHeight();

		// 缩放值进行边界检测，防止出现白边
		if (rect.width() >= width) {
			if (rect.left > 0) {
				deltaX = -rect.left;
			}

			if (rect.right < width) {
				deltaX = width - rect.right;
			}
		}

		if (rect.height() >= height) {
			if (rect.top > 0) {
				deltaY = -rect.top;
			}

			if (rect.bottom < height) {
				deltaY = height - rect.bottom;
			}
		}

		// 如果宽度或高度小于控件的宽或高，让其居中
		if (rect.width() < width) {
			deltaX = width / 2 - rect.right + rect.width() / 2;
		}

		if (rect.height() < height) {
			deltaY = height / 2 - rect.bottom + rect.height() / 2;
		}

		mScaleMatix.postTranslate(deltaX, deltaY);
	}

	/**
	 * 
	 * 获得图片放大缩小后的宽和高，以及l,r,t,b
	 * 
	 * @return
	 */
	private RectF getMatrixRectF() {
		Matrix matrix = mScaleMatix;
		RectF rectF = new RectF();
		Drawable d = getDrawable();
		if (d != null) {
			rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
			matrix.mapRect(rectF);
		}
		return rectF;
	}

	@Override
	public boolean onScaleBegin(ScaleGestureDetector detector) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public void onScaleEnd(ScaleGestureDetector detector) {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.view.View.OnTouchListener#onTouch(android.view.View,
	 * android.view.MotionEvent)
	 */
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		mScaleGestureDetector.onTouchEvent(event);
		float x = 0;
		float y = 0;

		// 多点触控的触控手指数量
		int pointerCount = event.getPointerCount();
		for (int i = 0; i < pointerCount; i++) {
			x += event.getX();
			y += event.getY();
		}

		// 获得多点触控中心坐标的位置
		x /= pointerCount;
		y /= pointerCount;

		if (mLastPointerCount != pointerCount) {
			isCanDrag = false;
			mLastX = x;
			mLastY = y;
		}
		mLastPointerCount = pointerCount;
		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE:
			float dx = x - mLastX;
			float dy = y - mLastY;

			if (!isCanDrag) {
				isCanDrag = isMoveAction(dx, dy);
			}

			if (isCanDrag) {
				RectF rectF = getMatrixRectF();
				if (getDrawable() != null) {
					isCheckLeftAndRight = isCheckTopAndBottom = true;

					if (rectF.width() < getWidth()) {
						isCheckLeftAndRight = false;
						dx = 0;
					}

					if (rectF.height() < getHeight()) {
						isCheckTopAndBottom = false;
						dy = 0;
					}

					mScaleMatix.postTranslate(dx, dy);
					checkBorderWhenTranslate();
					setImageMatrix(mScaleMatix);
				}
			}
			mLastX = x;
			mLastY = y;
			break;
		case MotionEvent.ACTION_UP:
			mLastPointerCount = 0;
			break;
		case MotionEvent.ACTION_CANCEL:
			mLastPointerCount = 0;
			break;
		default:
			break;
		}

		return true;
	}

	/**
	 * 移动时，检查边界
	 */
	private void checkBorderWhenTranslate() {
		RectF rectF = getMatrixRectF();
		float deltaX = 0;
		float deltaY = 0;

		int width = getWidth();
		int height = getHeight();

		if (rectF.top > 0 && isCheckTopAndBottom) {
			deltaY = -rectF.top;
		}

		if (rectF.bottom < height && isCheckTopAndBottom) {
			deltaY = height - rectF.bottom;
		}

		if (rectF.left > 0 && isCheckLeftAndRight) {
			deltaX = -rectF.left;
		}
		if (rectF.right < width && isCheckLeftAndRight) {
			deltaX = width - rectF.right;
		}
		mScaleMatix.postTranslate(deltaX, deltaY);
	}

	/**
	 * 
	 * 判断是否move
	 * 
	 * @param dx
	 * @param dy
	 * @return
	 */
	private boolean isMoveAction(float dx, float dy) {
		return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
	}

}
